#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@Author          : ricsy
@File            : sphinx_terminal.py
@Create Time     : 2025/6/8 06:02
@Last Modified   :
@Description     : 终端命令模拟插件
"""
import re

from docutils import nodes
from docutils.nodes import raw
from docutils.parsers.rst import Directive, directives
from docutils.parsers.rst.directives import unchanged
from ipywidgets import widgets

from extensions.common import process_caption, validate_bool, validate_numeric
from sphinx.application import Sphinx


class TerminalDirective(Directive):
    """终端命令模拟指令（支持内容嵌入）"""

    required_arguments = 0  # 允许没有必需参数
    optional_arguments = 0  # 可选参数个数
    final_argument_whitespace = True  # 允许最后一个参数包含空格
    has_content = True  # 启用内容支持
    option_spec = {
        "prompt": unchanged,
        "shell": lambda arg: directives.choice(
            arg, ["bash", "zsh", "cmd", "powershell", "python"]
        ),
        "height": lambda arg: validate_numeric(arg, min_val=0, max_val=500),
        "title": unchanged,
        "platform": lambda arg: directives.choice(arg, ["windows", "linux", "mac"]),
        "user": unchanged,
        "blink": validate_bool,
        "interval": lambda arg: validate_numeric(arg, min_val=0.5, max_val=5),
        "color": unchanged,
        "style": lambda arg: directives.choice(
            arg, ["block", "classic", "bar", "underline"]
        ),
    }

    # 默认选项
    DEFAULT_OPTIONS = {
        "prompt": {
            "value": "$",
            "widget": widgets.Text,
            "desc": "提示符",
        },
        "shell": {
            "value": "bash",
            "widget": widgets.Dropdown,
            "desc": "终端类型",
            "options": option_spec.get("shell").__code__.co_consts[1],
        },
        "height": {
            "value": 300,
            "widget": widgets.FloatSlider,
            "desc": "终端高度",
            "params": {
                "min": 120.0,
                "max": 300.0,
                "step": 0.1,
                "readout_format": ".1f",
            },
        },
        "title": {
            "value": "",
            "widget": widgets.Text,
            "desc": "窗口标题",
        },
        "platform": {
            "value": "windows",
            "widget": widgets.Dropdown,
            "desc": "平台类型",
            "options": option_spec.get("platform").__code__.co_consts[1],
        },
        "user": {
            "value": "",
            "widget": widgets.Text,
            "desc": " 用户名称",
        },
        "blink": {"value": False, "widget": widgets.Checkbox, "desc": "光标闪烁"},
        "interval": {
            "value": 0.8,
            "widget": widgets.FloatSlider,
            "desc": "闪烁间隔",
            # 光标闪烁间隔的默认值通常为 0.8 秒（人机工程学研究验证的舒适频率），避免视觉疲劳的最佳平衡点且人眼最小感知间隔：约 0.5 秒
            "params": {"min": 0.8, "max": 5.0, "step": 0.1, "readout_format": ".1f"},
        },
        "color": {
            "value": "#62ed8b",
            "widget": widgets.ColorPicker,
            "desc": "光标颜色",
        },
        "style": {
            "value": "block",
            "widget": widgets.Dropdown,
            "desc": "光标样式",
            "options": option_spec.get("style").__code__.co_consts[1],
        },
    }

    PLATFORM_ICONS = {
        "windows": "",  # Nerd Font Windows 图标
        "linux": "",  # Nerd Font Linux 图标
        "mac": "",  # Nerd Font Apple 图标
    }

    DEFAULT_SHELL_ICONS = " "
    SHELL_ICONS = {
        "bash": "",  # Nerd Font Bash 图标
        "zsh": "󰰶",  # Nerd Font Zsh 图标
        "cmd": " ",  # Nerd Font Cmd 图标
        "powershell": " ",  # Nerd Font PowerShell 图标
        "python": "",  # Nerd Font Python 图标
    }

    def get_default_value(self):
        return {k: v["value"] for k, v in self.DEFAULT_OPTIONS.items()}

    def run(self):
        # 获取参数
        default_value = self.get_default_value()
        options = {**default_value, **self.options}

        # 确定提示符
        prompt = options["prompt"].strip()
        username = options["user"].strip()
        platform = options["platform"].lower().strip()
        # 创建终端容器
        terminal_node = nodes.container(classes=["terminal-wrapper"])

        shell_type = ""
        if "shell" in self.options:
            shell_type = self.options.get("shell", "").lower()
            if shell_type in ["cmd", "powershell"]:
                platform = "windows"

        if shell_type == "":
            shell_type = default_value["shell"]

        # 添加运行平台属性
        if platform in self.PLATFORM_ICONS:
            terminal_node.attributes["data-platform"] = platform
            terminal_node["classes"].append(f"platform-{platform}")

        # 添加 shell 属性
        terminal_node.attributes["data-shell"] = shell_type
        terminal_node["classes"].append(f"shell-{shell_type}")

        # 创建标题栏
        if "title" in self.options:
            # 创建支持 HTML 的标题节点
            title_node = nodes.container(classes=["terminal-title"])
            title_raw = raw(
                "", process_caption(self, self.options["title"]), format="html"
            )
            title_paragraph = nodes.paragraph("", "", title_raw)
            title_node += title_paragraph

            terminal_node += title_node

        # 创建内容区域
        content_node = nodes.container(classes=["terminal-content"])

        # 处理每行内容
        for line in self.content:
            line = line.strip()
            if prompt and line.startswith(prompt.strip()):  # 带提示符的行
                # 提取工作目录信息
                cwd_match = re.search(r"@cwd=(.*?)@", line)
                if cwd_match:
                    cwd = cwd_match.group(1).strip()
                    # 创建路径显示节点
                    path_node = nodes.paragraph(
                        text=f"📁{cwd}", classes=["terminal-path-line"]
                    )
                    content_node += path_node
                    line = line.replace(f"@cwd={cwd}@", "").strip()

                # 提取耗时信息
                time_value = None
                time_match = re.search(r"@time=(.*?)@", line)
                if time_match:
                    time_value = time_match.group(1).strip()
                    line = line.replace(f"@time={time_value}@", "").strip()

                # 创建带系统图标、用户名和提示符的行
                prompt_parts = []

                # 添加系统图标
                if platform in self.PLATFORM_ICONS:
                    system_icon = nodes.inline("", self.PLATFORM_ICONS[platform])
                    system_icon["classes"] = ["terminal-platform-icon"]
                    prompt_parts.append(system_icon)
                    prompt_parts.append(nodes.Text(" "))

                # 添加提示符
                prompt_icon = self.SHELL_ICONS.get(shell_type, self.DEFAULT_SHELL_ICONS)
                prompt_node = nodes.inline(
                    text=prompt_icon, classes=["terminal-shell-icon"]
                )
                prompt_parts.append(prompt_node)
                prompt_parts.append(nodes.Text(""))

                # 添加用户名
                if username:
                    user_node = nodes.inline(text=username, classes=["terminal-user"])
                    prompt_parts.append(user_node)
                    prompt_parts.append(nodes.Text(" "))

                # 添加分隔符
                sep_node = nodes.inline(text="➜ ", classes=["terminal-sep"])
                prompt_parts.append(sep_node)

                # 添加耗时信息
                if time_value is not None:
                    time_node = nodes.inline(
                        text=f" {time_value}", classes=["terminal-command-time"]
                    )
                    prompt_parts.append(time_node)

                # 添加命令文本
                text_node = nodes.Text(line[len(prompt) :].strip())
                prompt_parts.append(text_node)

                # 添加光标
                if options["blink"]:
                    cursor_html_content = f"""<span class="terminal-cursor terminal-cursor-blink terminal-cursor-{options['style']}"style="--cursor-color: {options['color']}; --cursor-interval: {float(options['interval'])}s;"></span>"""
                    cursor_node = nodes.raw("", cursor_html_content, format="html")
                    prompt_parts.append(cursor_node)

                # 组合所有部分
                para = nodes.paragraph("", "", *prompt_parts)
            else:
                # 普通输出行
                para = nodes.paragraph("", "", nodes.Text(line))

            para["classes"].append("terminal-line")
            content_node += para

        terminal_node += content_node
        return [terminal_node]


def setup(app: Sphinx):
    app.add_directive("terminal", TerminalDirective)
    app.add_css_file("extensions/css/terminal.css")
